package com.lap.framework.common.tool;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.lap.framework.common.enums.JsonSerializationFeature;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Json 工具类
 *
 * @author Shuisheng Lao(劳水生)
 * @version 0.0.1
 */
public final class JsonUtil {

  private static final ObjectMapper DEFAULT_MAPPER = createDefaultMapper();
  private static final Map<JsonSerializationFeature, ObjectMapper> MAPPER_CACHE =
      new ConcurrentHashMap<>(JsonSerializationFeature.values().length);

  private static ObjectMapper createDefaultMapper() {
    return new ObjectMapper()
        .registerModule(new JavaTimeModule())
        .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
        .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
        .enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES)
        .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
        .setSerializationInclusion(JsonInclude.Include.NON_NULL);
  }

  private JsonUtil() {
    throw new AssertionError("Utility class should not be instantiated");
  }

  /**
   * 获取配置后的ObjectMapper
   *
   * @param features 序列化特性配置
   * @return 配置好的ObjectMapper
   */
  public static ObjectMapper getConfiguredMapper(JsonSerializationFeature... features) {
    if (features == null || features.length == 0) {
      return DEFAULT_MAPPER;
    }

    return MAPPER_CACHE.computeIfAbsent(
        features.length == 1 ? features[0] : JsonSerializationFeature.COMBINED,
        key -> createMapperWithFeatures(DEFAULT_MAPPER.copy(), features));
  }

  private static ObjectMapper createMapperWithFeatures(
      ObjectMapper mapper, JsonSerializationFeature[] features) {
    // 先处理非时间特性
    for (JsonSerializationFeature feature : features) {
      switch (feature) {
        case INDENT_OUTPUT:
          mapper.enable(SerializationFeature.INDENT_OUTPUT);
          break;
        case WRAP_ROOT_VALUE:
          mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
          break;
        case WRITE_ENUMS_USING_TO_STRING:
          mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
          break;
        case WRITE_NULL_MAP_VALUES:
          mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
          break;
      }
    }

    // 单独处理时间戳特性（避免冲突）
    boolean writeDateAsTimestamps =
        Arrays.stream(features).anyMatch(f -> f == JsonSerializationFeature.WRITE_DATE_TIMESTAMPS);

    // 确保配置一致
    if (writeDateAsTimestamps) {
      mapper.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);
      mapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    }

    return mapper;
  }

  /**
   * 类型转换
   *
   * @param <T> 目标类型
   * @param source 源对象
   * @return 转换后的对象
   */
  public static <T> T convert(Object source) {
    return convert(source, new TypeReference<>() {});
  }

  /**
   * 类型转换（支持复杂类型）
   *
   * @param <T> 目标类型
   * @param source 源对象
   * @param valueType 目标类型参考
   * @return 转换后的对象
   */
  public static <T> T convert(Object source, TypeReference<T> valueType) {
    if (source == null) return null;
    try {
      return DEFAULT_MAPPER.convertValue(source, valueType);
    } catch (IllegalArgumentException e) {
      throw new JsonConversionException(
          "Failed to convert object of type: " + source.getClass().getName(), e);
    }
  }

  /**
   * JSON字符串转对象
   *
   * @param <T> 目标类型
   * @param json JSON字符串
   * @param clazz 目标类
   * @return 转换后的对象
   */
  public static <T> T toObj(String json, Class<T> clazz) {
    if (json == null || json.isBlank()) return null;
    try {
      return DEFAULT_MAPPER.readValue(json, clazz);
    } catch (JsonProcessingException e) {
      throw new JsonParseException(
          "Failed to parse JSON to " + clazz.getName() + ". JSON: " + safeSubstring(json, 50), e);
    }
  }

  /**
   * JSON字符串转复杂类型
   *
   * @param <T> 目标类型
   * @param json JSON字符串
   * @param typeReference 类型参考
   * @return 转换后的对象
   */
  public static <T> T toObj(String json, TypeReference<T> typeReference) {
    if (json == null || json.isBlank()) return null;
    try {
      return DEFAULT_MAPPER.readValue(json, typeReference);
    } catch (JsonProcessingException e) {
      throw new JsonParseException(
          "Failed to parse JSON to " + typeReference.getType().getTypeName(), e);
    }
  }

  /**
   * JSON字符串转Map
   *
   * @param json JSON字符串
   * @return Map对象，输入无效时返回空Map
   */
  @SuppressWarnings("unchecked")
  public static Map<String, Object> toMap(String json) {
    if (json == null || json.isBlank()) return Collections.emptyMap();
    try {
      return DEFAULT_MAPPER.readValue(json, Map.class);
    } catch (JsonProcessingException e) {
      throw new JsonParseException("Failed to parse JSON to Map", e);
    }
  }

  /**
   * 对象转JSON字符串
   *
   * @param object 目标对象
   * @return JSON字符串
   */
  public static String toJson(Object object) {
    return toJson(object, new JsonSerializationFeature[0]);
  }

  /**
   * 对象转JSON字符串（支持配置输出特性）
   *
   * @param object 目标对象
   * @param features 序列化特性
   * @return JSON字符串
   */
  public static String toJson(Object object, JsonSerializationFeature... features) {
    if (object == null) return null;
    try {
      return getConfiguredMapper(features).writeValueAsString(object);
    } catch (JsonProcessingException e) {
      throw new JsonGenerationException(
          "Failed to serialize object of type: " + object.getClass().getName(), e);
    }
  }

  /**
   * 对象转字节数组
   *
   * @param object 目标对象
   * @return 字节数组
   */
  public static byte[] toBytes(Object object) {
    return toBytes(object, new JsonSerializationFeature[0]);
  }

  /**
   * 对象转字节数组（支持配置输出特性）
   *
   * @param object 目标对象
   * @param features 序列化特性
   * @return 字节数组
   */
  public static byte[] toBytes(Object object, JsonSerializationFeature... features) {
    if (object == null) return null;
    try {
      return getConfiguredMapper(features).writeValueAsBytes(object);
    } catch (JsonProcessingException e) {
      throw new JsonGenerationException(
          "Failed to serialize object of type: " + object.getClass().getName(), e);
    }
  }

  /**
   * 美化输出JSON（调试用）
   *
   * @param object 目标对象
   * @return 格式化后的JSON字符串
   */
  public static String pretty(Object object) {
    return toJson(object, JsonSerializationFeature.INDENT_OUTPUT);
  }

  // 辅助方法：安全截取字符串
  private static String safeSubstring(String str, int maxLength) {
    if (str == null) return "null";
    return str.length() > maxLength ? str.substring(0, maxLength) + "..." : str;
  }

  // 自定义异常类型
  public static class JsonParseException extends UncheckedIOException {
    public JsonParseException(String message, JsonProcessingException cause) {
      super(message, cause);
    }
  }

  public static class JsonGenerationException extends UncheckedIOException {
    public JsonGenerationException(String message, JsonProcessingException cause) {
      super(message, cause);
    }
  }

  public static class JsonConversionException extends RuntimeException {
    public JsonConversionException(String message, Throwable cause) {
      super(message, cause);
    }
  }
}
